﻿
namespace QFramework
{
    using System;
    using System.Collections.Generic;
    using UnityEngine;
    using FairyGUI;

    public class FGUIManager : QMgrBehaviour, ISingleton
    {
        List<MgrGcomponent>                     m_LayerCtrList = new List<MgrGcomponent>();             //层级
        Dictionary<string, UIPackage>           m_HasAddPack = new Dictionary<string, UIPackage>();     //包名
        Dictionary<string, FGUIBehaviour>       m_OpenGcList = new Dictionary<string, FGUIBehaviour>(); //UI

        /// <summary>
        /// 初始化时以高适配768 * 1280
        /// </summary>
        public void OnSingletonInit()
        {
            SetResolution(768, 1280, UIContentScaler.ScreenMatchMode.MatchHeight);
        }

        protected override void SetupMgrId()
        {
            mMgrId = QMgrID.UI;
        }

        private static FGUIManager mInstance;

        public static FGUIManager Instance
        {
            get
            {
                if (null == mInstance)
                {
                    mInstance = FindObjectOfType<FGUIManager>();
                }

                if (null == mInstance)
                {
                    Instantiate(Resources.Load<GameObject>("FGUIManager"));
                    mInstance = QMonoSingletonProperty<FGUIManager>.Instance;
                    mInstance.name = "FGUIManager";
                    DontDestroyOnLoad(mInstance);
                }
                return mInstance;
            }
        }

        ResLoader m_Loader = ResLoader.Allocate();

        /// <summary>
        /// 加载资源包.
        /// </summary>
        /// <param name="assetName">FGUI 包属性</param>
        /// <returns></returns>
        public AssetBundle[] GetAb(string assetName)
        {
            string[] abNamelist = GetAbName(assetName);
            AssetBundle[] list = new AssetBundle[2];

            list[0] = m_Loader.LoadSync<AssetBundle>(abNamelist[0]);
            list[1] = m_Loader.LoadSync<AssetBundle>(abNamelist[1]);
            return list;
        }

        /// <summary>
        /// 根据资源名获得 数据AB包和美术资源AB包
        /// </summary>
        /// <param name="assetName"></param>
        /// <returns></returns>
        private string[] GetAbName(string assetName)
        {
            string[] abNameList = new string[2];
            AssetData data = AssetDataTable.Instance.GetAssetData(assetName);
            if (data != null)
                abNameList[0] = data.OwnerBundleName;

            assetName += "@sprites";
            data = AssetDataTable.Instance.GetAssetData(assetName);
            abNameList[1] = data.OwnerBundleName;
            return abNameList;
        }

        Dictionary<string, AbName>          m_FullName4comandpack = new Dictionary<string, AbName>();
        Dictionary<AbName, AsynData>        m_CallbackList = new Dictionary<AbName, AsynData>();

        public class AsynData
        {
            public Action<IUIBehaviour> _CreateCallBack;
            public string _FullName;
            public IUIData _Data;
            public int _level;
        }

        public AsynData OpenPanelAsyn(string FullName, int m_level = UILevel.Common, IUIData m_data = null, Action<IUIBehaviour> m_ui = null)
        {
            string packName = GetABInfo(FullName).PackName;
            string Component = GetABInfo(FullName).ComName;

            IUIBehaviour tempui = hasUI(FullName, packName);
            if (tempui != null)
            {
                m_ui.InvokeGracefully(tempui);
            }

            UIPackage.CreateObjectAsync(packName, Component, UICreateCallBack);
            AsynData asynData = new AsynData() { _CreateCallBack = m_ui, _FullName = FullName, _level = m_level, _Data = m_data };
            m_CallbackList.Add(new AbName(packName, Component), asynData);

            return asynData;
        }

        /// <summary>
        /// 异步打开UI回调
        /// </summary>
        /// <param name="UI"></param>
        void UICreateCallBack(GObject UI)
        {
            AbName flagAbName = null;
            foreach (var item in m_CallbackList)
            {
                if (item.Key.ComName == UI.gameObjectName && item.Key.PackName == UI.packageItem.owner.name)
                {
                    flagAbName = item.Key;
                    item.Value._CreateCallBack.InvokeGracefully(CreateUI((GComponent)UI, item.Value._FullName, item.Value._level, item.Value._Data));
                }
            }

            if (flagAbName != null)
            {
                m_CallbackList.Remove(flagAbName);
            }
        }

        /// <summary>
        /// 判断是否存在UI
        /// </summary>
        /// <param name="FullName"></param>
        /// <param name="packName"></param>
        /// <returns></returns>
        IUIBehaviour hasUI(string FullName,string packName)
        {
            if (!m_HasAddPack.ContainsKey(FullName))
            {
                AssetBundle[] m_Bundle = GetAb(packName);
                if (m_Bundle != null)
                {
                    m_HasAddPack.Add(FullName, UIPackage.AddPackage(m_Bundle[0], m_Bundle[1], false));
                }
            }

            if (m_OpenGcList.ContainsKey(FullName))
            {
                m_OpenGcList[FullName].Show();
                return m_OpenGcList[FullName];
            }

            return null;
        }

        public IUIBehaviour OpenPanel(string FullName, int m_level = UILevel.Common, IUIData m_data = null)
        {
            string packName = GetABInfo(FullName).PackName;
            string Component = GetABInfo(FullName).ComName;

            IUIBehaviour tempui = hasUI(FullName, packName);
            if (tempui != null)
                return tempui;

            GComponent view = UIPackage.CreateObject(packName, Component).asCom;
            return CreateUI(view, FullName, m_level, m_data);
        }

        IUIBehaviour CreateUI(GComponent view,string FullName,int m_level,IUIData m_data)
        {
            GRoot.inst.AddChild(view);

            Type t = Type.GetType(FullName);
            FGUIBehaviour m_Behaviour = view.displayObject.gameObject.AddComponent(t) as FGUIBehaviour;

            m_Behaviour.m_Compoent = view;
            m_Behaviour.Init(m_data);

            m_LayerCtrList.Add(new MgrGcomponent() { _CurrentLevel = m_level, _view = view });

            if (m_LayerCtrList.Count > 1)
                m_LayerCtrList.Sort(Compare);

            for (int i = 0; i < m_LayerCtrList.Count; i++)
            {
                GRoot.inst.SetChildIndex(m_LayerCtrList[i]._view, i);
            }

            m_OpenGcList.Add(FullName, m_Behaviour);

            return m_Behaviour;
        }

        /// <summary>
        /// 通过全名获得包名和组件名
        /// </summary>
        /// <param name="FullName"></param>
        /// <returns></returns>
        AbName GetABInfo(string FullName)
        {
            if (m_FullName4comandpack.ContainsKey(FullName))
            {
                return m_FullName4comandpack[FullName];
            }

            string[] nameSplits = FullName.Split('.');
            string Name = nameSplits[nameSplits.Length - 1];

            int packIndex = Name.IndexOf("_");
            string packName = Name.Substring(0, packIndex);
            string Component = Name.Substring(packIndex + 1, Name.Length - packIndex - 1);

            m_FullName4comandpack.Add(FullName, new AbName() { ComName = Component, PackName = packName });

            return m_FullName4comandpack[FullName];
        }

        /// <summary>
        /// 排序设置层级
        /// </summary>
        /// <param name="m1"></param>
        /// <param name="m2"></param>
        /// <returns></returns>
        int Sort(MgrGcomponent m1, MgrGcomponent m2)
        {
            return m1._CurrentLevel.CompareTo(m2._CurrentLevel);
        }

        /// <summary>
        /// 比对排序
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <returns></returns>
        private int Compare(MgrGcomponent left, MgrGcomponent right)
        {
            if (left._CurrentLevel > right._CurrentLevel)
                return 1;
            else if (left._CurrentLevel == right._CurrentLevel)
                return -1;
            else
                return -1;
        }

        /// <summary>
        /// 关闭窗口
        /// </summary>
        /// <param name="Component"></param>
        public void HidePanel(string FullName)
        {
            if (m_OpenGcList.ContainsKey(FullName))
            {
                m_OpenGcList[FullName].Hide();
            }
        }

        /// <summary>
        /// 删除窗口
        /// </summary>
        /// <param name="Component"></param>
        public void DestroyPanel(string FullName)
        {
            if (m_OpenGcList.ContainsKey(FullName))
            {
                m_LayerCtrList.ForEach(x => { if (x._view == m_OpenGcList[FullName].m_Compoent) m_LayerCtrList.Remove(x); });
                m_OpenGcList[FullName].Dispose();
                m_OpenGcList.Remove(FullName);
            }
        }

        /// <summary>
        /// 释放包
        /// </summary>
        /// <param name="PackName"></param>
        public void ReleasePack(string FullName)
        {          
            if (m_HasAddPack.ContainsKey(FullName))
            {
                AbName packInfo;
                m_FullName4comandpack.TryGetValue(FullName,out packInfo);

                if (packInfo != null)
                {
                    foreach (var item in m_FullName4comandpack)
                    {
                        if (item.Value.PackName == packInfo.PackName)
                        {
                            DestroyPanel(item.Key);
                        }
                    }

                    string[] list = GetAbName(packInfo.PackName);
                    foreach (var item in list)
                    {
                        m_Loader.ReleaseRes(item);
                        Log.I("卸载资源" + item);
                    }
                }
                else
                {
                    Log.I("没找到"+FullName);
                }
                UIPackage.RemovePackage(m_HasAddPack[FullName].name);
                m_HasAddPack.Remove(FullName);
            }
            else
            {
                Log.I("不存在UI"+ FullName);
            }
        }

        /// <summary>
        /// 释放所有包
        /// </summary>
        public void ReleaseAllPack()
        {
            foreach (var item in m_OpenGcList)
            {
                item.Value.Dispose();
            }
            m_HasAddPack.Clear();
            m_OpenGcList.Clear();
            m_LayerCtrList.Clear();
            m_Loader.ReleaseAllRes();
            m_FullName4comandpack.Clear();
            m_CallbackList.Clear();
            UIPackage.RemoveAllPackages();
        }

        /// <summary>
        /// 卸载所有窗口
        /// </summary>
        public void DestroyAllPanel()
        {
            m_OpenGcList.ForEach((x, y) => y.Dispose());
            m_OpenGcList.Clear();
            m_LayerCtrList.Clear();
        }

        /// <summary>
        /// 设置宽高比
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="m_Model">适配模式</param>
        public void SetResolution(int width, int height, UIContentScaler.ScreenMatchMode m_Model = UIContentScaler.ScreenMatchMode.MatchHeight)
        {
            GRoot.inst.SetContentScaleFactor(width, height, m_Model);
        }
    }

    /// <summary>
    /// 快捷接口
    /// </summary>
    public static class FUIMgr
    {
        public static T OpenPanel<T>(int m_level = UILevel.Common, IUIData m_data = null) where T : FGUIBehaviour
        {
            string name = typeof(T).ToString();
            return FGUIManager.Instance.OpenPanel(name, m_level, m_data) as T;
        }

        public static FGUIManager.AsynData OpenPanelAsyn<T>(int m_level = UILevel.Common, IUIData m_data = null, Action<IUIBehaviour> m_Event = null) where T : FGUIBehaviour
        {
            string name = typeof(T).ToString();
            return FGUIManager.Instance.OpenPanelAsyn(name, m_level, m_data, m_Event);
        }

        public static void ClosePanle<T>()
        {
            string name = typeof(T).ToString();
            FGUIManager.Instance.HidePanel(name);
        }

        public static void ReleasePack<T>()
        {
            string name = typeof(T).ToString();
            FGUIManager.Instance.ReleasePack(name);
        }

        public static void ReleaseAllPack()
        {
            FGUIManager.Instance.ReleaseAllPack();
        }

        public static void DestroyPanle<T>()
        {
            string name = typeof(T).ToString();
            FGUIManager.Instance.DestroyPanel(name);
        }

        public static void ClosePanle(string c)
        {
            FGUIManager.Instance.HidePanel(c);
        }

        public static void DestroyPanle(string c)
        {
            FGUIManager.Instance.DestroyPanel(c);
        }

        public static void DestroyAllPanle()
        {
            FGUIManager.Instance.DestroyAllPanel();
        }

        public static void SetResolution(int width, int height, UIContentScaler.ScreenMatchMode m_Model = UIContentScaler.ScreenMatchMode.MatchHeight)
        {
            FGUIManager.Instance.SetResolution(width, height, m_Model);
        }
    }

    [System.Serializable]
    public class MgrGcomponent
    {
        public int _CurrentLevel;
        public GComponent _view;
    }

    public class AbName
    {
        public string PackName;
        public string ComName;

        public AbName() { }

        public AbName(string PackName, string ComName)
        {
            this.PackName = PackName;
            this.ComName = ComName;
        }
    }
}
